/*******************************************************************************/
/*                                                                             */
/*  Copyright (c) 2009: Peter Schregle,                                        */
/*  All rights reserved.                                                       */
/*                                                                             */
/*  This file is part of the Property Library.                                 */
/*                                                                             */
/*  Redistribution of the Property Library and use in source and binary forms, */
/*  with or without modification, are permitted provided that the following    */
/*  conditions are met:                                                        */
/*  1. Redistributions of source code must retain the above copyright notice,  */
/*     this list of conditions and the following disclaimer.                   */
/*  2. Redistributions in binary form must reproduce the above copyright       */
/*     notice, this list of conditions and the following disclaimer in the     */
/*     documentation and/or other materials provided with the distribution.    */
/*  3. Neither the name of Peter Schregle nor the names of other contributors  */
/*     may be used to endorse or promote products derived from this software   */
/*     without specific prior written permission.                              */
/*                                                                             */
/*  THIS SOFTWARE IS PROVIDED BY PETER SCHREGLE AND CONTRIBUTORS 'AS IS' AND   */
/*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE      */
/*  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE */
/*  ARE DISCLAIMED. IN NO EVENT SHALL PETER SCHREGLE OR CONTRIBUTORS BE LIABLE */
/*  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL */
/*  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS    */
/*  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)      */
/*  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,        */
/*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN   */
/*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE            */
/*  POSSIBILITY OF SUCH DAMAGE.                                                */
/*                                                                             */
/*******************************************************************************/


#include "../../include/pl/property.h"
#include "intrin.h"
#include <iostream>

/******************************************************************************/
/*                                                                            */
/* cpu_clocks_32                                                              */
/*                                                                            */
/******************************************************************************/

/// Return the number of clocks since the processor was powered up.
//!
//! With modern processors there are a few gotchas related to this function.
//!
//! The function internally uses the RDTSC assembler instruction, which has the
//! following limitations you should know about:
//! - The timing information is locked to the cycle counter of the processor.
//! - Dual core or multi core processors do not guarantee synchronization
//! between cycle counters.
//! - CPU frequency is not fixed.
//!
//! Nevertheless, the function is a good measurement tool if you want to judge
//! the relative performance of an algorithm in some measurement such as
//! clocks per pixel.
//!
//! \return The number of clocks since the processor was powered up. The 
//! result is returned in a 32 bit unsigned integer. It can count up to 
//! 4294967296 counts, which - on a 3 MHz CPU - translates to 1.3 seconds
//! before it wraps.
//!
//! Wrap around may lead to incorrect measurements since the difference between
//! a counter value and a wrapped around counter value is meaningless. With the
//! 32bit counter wrap around occurs very often.
inline unsigned int cpu_clocks_32()
{
	// The RDTSC statement returns the number of clocks since the processor was
	// powered up in eax/edx. The intrinsic is used, because the 64bit compiler
	// does not support inline assembly, like:
	//	_asm {
	//		RDTSC
	//	}
	// the return statement can be omitted, since the data is already in eax

	return (unsigned int)__rdtsc();
}

int value_;

inline int & getter()
{
	return value_;
}

inline void setter(int const& value)
{
	value_ = value;
}

int main()
{
	std::cout << "Benchmark of the Property Library" << std::endl;
	std::cout << "=================================" << std::endl << std::endl;

	unsigned int start = 0;
	const int loops = 1000000;

	{
		int int_[loops];

		int a;
		start = cpu_clocks_32();
		for (int i=0; i<loops; ++i)
			a = int_[i];
		double clocks_read_int = (cpu_clocks_32() - start) / (double)loops;

		start = cpu_clocks_32();
		for (int i=0; i<loops; ++i)
			int_[i] = a;
		double clocks_write_int = (cpu_clocks_32() - start) / (double)loops;


		pl::property_rwf<int> rwf[loops];

		int b;
		start = cpu_clocks_32();
		for (int i=0; i<loops; ++i)
			b = rwf[i];
		double clocks_read_rwf = (cpu_clocks_32() - start) / (double)loops;

		start = cpu_clocks_32();
		for (int i=0; i<loops; ++i)
			rwf[i] = b;
		double clocks_write_rwf = (cpu_clocks_32() - start) / (double)loops;


		pl::property_rof<int> rof[loops];

		int c;
		start = cpu_clocks_32();
		for (int i=0; i<loops; ++i)
			c = rof[i];
		double clocks_read_rof = (cpu_clocks_32() - start) / (double)loops;

		double clocks_write_rof = 0;


		pl::property_wof<int> wof[loops];

		double clocks_read_wof = 0;

		start = cpu_clocks_32();
		for (int i=0; i<loops; ++i)
			wof[i] = c;
		double clocks_write_wof = (cpu_clocks_32() - start) / (double)loops;

		std::cout << "Field Property \tint\trwf\trof\twof" << std::endl;
		std::cout << "Read           \t" << clocks_read_int << "\t" << clocks_read_rwf << "\t" << clocks_read_rof << "\t" << clocks_read_wof << std::endl;
		std::cout << "Write          \t" << clocks_write_int << "\t" << clocks_write_rwf << "\t" << clocks_write_rof << "\t" << clocks_write_wof << std::endl;
		std::cout << std::endl;
	}
}


